home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 …ember: Reference Library / Apple Developer Reference Library (December 1999) (Disk 1).iso / pc / technical documentation / develop / develop issue 27 / develop issue 27 code / internet config assistant / toolkit / cfonts.cp < prev    next >
Encoding:
Text File  |  1996-06-08  |  12.1 KB  |  724 lines

  1. /*
  2.     File:        CFonts.cp
  3.  
  4.     Contains:    Font manager wrapper classes
  5.  
  6.     Written by:    Arno Gourdol
  7.  
  8.     Copyright:    © 1994-1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <1>     3/31/96    arno   First created.
  13.  
  14. */
  15.  
  16. #include "CFonts.h"
  17.  
  18.  
  19. #include "assert.h"
  20. #include "macros.h"
  21.  
  22. #include "NeoTextBox.h"
  23.  
  24.  
  25. //    ---------------------------------------------------------------------
  26. //
  27. //    CFontSpec
  28. //
  29. //    The CFontSpec class manages font information (script, font, size, 
  30. //    style). It caches the current font settings to avoids doing
  31. //    uneccessary Toolbox calls. It also caches font metrics for the 
  32. //    same reason.
  33. //
  34. //    A typical use is:
  35. /*
  36.   CFontSpec    saveFontSpec;
  37.   CFontSpec    smallFontSpec(smSystemScript, kSmallFont);
  38.   CFontSpec    systemFontSpec(smSystemScript, kSystemFont);
  39.  
  40.   saveFontSpec.Save();        // Saves the current font information
  41.  
  42.   // ... more inits
  43.  
  44.   systemFontSpec.DrawString("Hello");    // Use the system font
  45.  
  46.   //...
  47.  
  48.   smallFontSpec.DrawString("word");    // Use the small default font
  49.  
  50.   saveFontSpec.Restore();        // Restore the font information
  51.  
  52. */
  53. //
  54. //    ---------------------------------------------------------------------
  55.  
  56.  
  57.  
  58. Boolean CFontSpec::pSystemFontInited = false;
  59. CFontSpec pSystemFontSpec;    // should belong to CFontSpec as a static member but constructors
  60.                             // aren't called from CFM initialization
  61.  
  62. Boolean CFontSpec::pSmallFontInited = false;
  63. CFontSpec pSmallFontSpec;    // should belong to CFontSpec as a static member but constructors
  64.                             // aren't called from CFM initialization
  65.  
  66. Handle CFontSpec::pItl0 = NULL;
  67. Handle CFontSpec::pItl1 = NULL;
  68. Handle CFontSpec::pItl2 = NULL;
  69.  
  70. short CFontSpec::fFontToScriptCacheFont = 0;
  71. ScriptCode CFontSpec::fFontToScriptCacheScript = smSystemScript;
  72.     
  73. ScriptCode CFontSpec::fSupportsCondenseCacheScript = smRoman;
  74. Boolean CFontSpec::fSupportsCondenseCache = true;
  75.     
  76. ScriptCode CFontSpec::fScriptIsRTLCacheScript = smRoman;
  77. Boolean CFontSpec::fScriptIsRTLCache = false;            // Roman is not right to left
  78.     
  79. ScriptCode CFontSpec::fScriptFontCacheScript = smAllScripts;
  80. short CFontSpec::fScriptFontCacheFont = 1049;
  81. long CFontSpec::fScriptFontCacheFontAndSize = 0;
  82.  
  83.  
  84. //
  85. //    CFontSpec::CFontSpec
  86. //
  87. //
  88.  
  89. CFontSpec::CFontSpec(void) :
  90.     fScript(smNoScript),
  91.     fLineHeight(-10),
  92.     fFont(-10),
  93.     fStyle(normal),
  94.     fMode(srcOr)    
  95. {
  96. #ifndef NDEBUG
  97.     fSaveCount = 0;
  98. #endif
  99.  
  100. }
  101.  
  102.  
  103.  
  104. //
  105. //    CFontSpec::CFontSpec
  106. //
  107. //
  108.  
  109. CFontSpec::CFontSpec(ScriptCode scriptCode,
  110.                      FontCode font) :
  111.     fScript(smNoScript),
  112.     fLineHeight(-10),
  113.     fFont(-10),
  114.     fStyle(normal),
  115.     fMode(srcOr)
  116. {
  117. #ifndef NDEBUG
  118.     fSaveCount = 0;
  119. #endif
  120.  
  121.     this->SetFont(scriptCode, font);
  122. }
  123.  
  124.  
  125.  
  126. //
  127. //    CFontSpec::~CFontSpec
  128. //
  129. //    Check that the calls to Save and Restore were balanced
  130. //
  131.  
  132. CFontSpec::~CFontSpec()
  133. {
  134. #ifndef NDEBUG
  135.     assert(fSaveCount == 0);
  136. #endif
  137. }
  138.  
  139.  
  140.  
  141. //
  142. //    CFontSpec::FontToScript
  143. //
  144. //
  145.  
  146. ScriptCode CFontSpec::FontToScript(short font)
  147. {
  148.     if (font == fFontToScriptCacheFont)
  149.     {
  150.         return fFontToScriptCacheScript;
  151.     }
  152.     else
  153.     {
  154.         fFontToScriptCacheScript = font;
  155.         return fFontToScriptCacheScript = ::FontToScript(font);
  156.     }
  157. }
  158.  
  159.  
  160.  
  161. //
  162. //    CFontSpec::SupportCondense
  163. //
  164. //
  165.  
  166. Boolean CFontSpec::SupportCondense(ScriptCode script)
  167. {
  168.     if (script == fSupportsCondenseCacheScript)
  169.     {
  170.         return fSupportsCondenseCache;
  171.     }
  172.     else
  173.     {
  174.         fSupportsCondenseCacheScript = script;
  175.         return fSupportsCondenseCache = ((::GetScriptVariable(script, smScriptValidStyles) & condense) != 0);
  176.     }
  177. }
  178.  
  179.  
  180.  
  181. //
  182. //    CFontSpec::ScriptIsRTL
  183. //
  184. //
  185.  
  186. Boolean CFontSpec::ScriptIsRTL(ScriptCode script)
  187. {
  188.     if (script == fScriptIsRTLCacheScript)
  189.     {
  190.         return fScriptIsRTLCache;
  191.     }
  192.     else
  193.     {
  194.         fScriptIsRTLCacheScript = script;
  195.         return fScriptIsRTLCache = (::GetScriptVariable(script, smScriptRight) != 0);
  196.     }
  197. }
  198.  
  199.  
  200.  
  201. //
  202. //    CFontSpec::ScriptFont
  203. //
  204. //
  205.  
  206. long CFontSpec::ScriptFont(ScriptCode script, short font)
  207. {
  208.     if ((script == fScriptFontCacheScript) && (font == fScriptFontCacheFont))
  209.     {
  210.         return fScriptFontCacheFontAndSize;
  211.     }
  212.     else
  213.     {
  214.         fScriptFontCacheScript = script;
  215.         fScriptFontCacheFont = font;
  216.         return fScriptFontCacheFontAndSize = ::GetScriptVariable(script, font);
  217.     }
  218. }
  219.  
  220.  
  221.  
  222. //
  223. //    CFontSpec::Save
  224. //
  225. //    Store in the object the current values for the font 
  226. //
  227.  
  228. void CFontSpec::Save(void)
  229. {
  230.     GrafPtr curPort;
  231.     GetPort(&curPort);
  232.  
  233.     // Read the values directly from the port data structure
  234.     // (berk)
  235.     fFont = curPort->txFont;
  236.     fScript = FontToScript(fFont);
  237.     fSize = curPort->txSize;
  238.     fStyle = curPort->txFace;
  239.     fMode = curPort->txMode;
  240.  
  241.     fLineHeight = 0;                            // Mark the font info as invalid
  242.  
  243. #ifndef NDEBUG
  244.     // Track how many times save and restore are called
  245.     fSaveCount++;
  246. #endif
  247.  
  248. }
  249.  
  250.  
  251.  
  252. //
  253. //    CFontSpec::Restore
  254. //
  255. //    Sets the current port font characteristics to those of the object,
  256. //    presumably stored by an earlier call to Save
  257. //
  258.  
  259. void CFontSpec::Restore()
  260. {
  261.     Use();
  262.  
  263. #ifndef NDEBUG
  264.     // Track how many times save and restore are called
  265.     fSaveCount--;
  266. #endif
  267.  
  268. }
  269.  
  270.  
  271.  
  272. //
  273. //    CFontSpec::SetFont
  274. //
  275. //
  276.  
  277. void CFontSpec::SetFont(ScriptCode scriptCode,
  278.                           FontCode font)
  279. {
  280.     // Check that the script code is in a reasonable range
  281.     // -2 is current script, -1 system script
  282.     // we ignore -3 = all scripts
  283.     // the last script, 32, is for uninterpreted symbols
  284.     assert((scriptCode >= -2) && (scriptCode <= 32));
  285.  
  286.     assert((font == kMonospacedFont) ||
  287.            (font == kPreferedFont) ||
  288.            (font == kSmallFont) ||
  289.            (font == kSystemFont) ||
  290.            (font == kApplicationFont) || 
  291.            (font == kHelpManagerFont));
  292.  
  293.     {
  294.         long fontAndSize;
  295.  
  296.         // Ask the Script manager what the font really is
  297.         fontAndSize = ScriptFont(scriptCode, font);
  298.  
  299.         // Set the font and size
  300.         fFont = HighWord(fontAndSize);
  301.         fSize = LowWord(fontAndSize);
  302.  
  303.         fScript = FontToScript(fFont);
  304.         fStyle = normal;
  305.         fRightToLeft = ScriptIsRTL(fScript);
  306.         fLineHeight = 0;                        // Note that the font information will need to be updated
  307.     }
  308. }
  309.  
  310.  
  311.  
  312. //
  313. //    CFontSpec::SetFont
  314. //
  315. //    Set the font named. 
  316. //    Return true if the font was found, false otherwise
  317. //    Use GetFont to get the name of the font that was substituted
  318. //
  319.  
  320. Boolean CFontSpec::SetFont(ScriptCode scriptCode,
  321.                            ConstStr255Param fontName)
  322. {
  323.     short font;
  324.     Boolean result = true;                        // Assume success
  325.  
  326.     ::GetFNum(fontName, &font);
  327.     SetFontID(font);
  328.  
  329.     if (font == 0)
  330.     {
  331.         // Either the font was not found or we asked for the 
  332.         // system font
  333.         {
  334.             Str255 systemFontName;
  335.  
  336.             ::GetFontName(0, systemFontName);
  337.             result = EqualString(fontName, systemFontName, false, false);
  338.         }
  339.         if (result == false)
  340.         {
  341.             // We didn't ask for the system font, i.e.
  342.             // the font was not found. Use the application font for the requested script
  343.             SetFont(scriptCode, kApplicationFont);
  344.             // ??? We could use a more elaborate substitution strategy
  345.         }
  346.     }
  347.  
  348.     return result;
  349. }
  350.  
  351.  
  352. //
  353. //    CFontSpec::SetFontID
  354. //
  355. //
  356.  
  357. void CFontSpec::SetFontID(short font)
  358. {
  359.     if (fFont != font)
  360.     {
  361.         fFont = font;
  362.         fScript = FontToScript(fFont);
  363.  
  364.         fLineHeight = 0;                        // Invalidate the font information
  365.     }
  366. }
  367.  
  368.  
  369.  
  370. //
  371. //    CFontSpec::SetSize
  372. //
  373. //
  374.  
  375. void CFontSpec::SetSize(short size)
  376. {
  377.     if (fSize != size)
  378.     {
  379.         fSize = size;
  380.  
  381.         fLineHeight = 0;                        // Invalidate the font information
  382.     }
  383. }
  384.  
  385.  
  386.  
  387. //
  388. //    CFontSpec::SetStyle
  389. //
  390. //
  391.  
  392. void CFontSpec::SetStyle(short style)
  393. {
  394.     if (fStyle != style)
  395.     {
  396.         // Check it's a valid style
  397.         assert(style <= 128);
  398.         assert((style & ::GetScriptVariable(fScript, smScriptValidStyles)) == style);
  399.  
  400.         fStyle = style;
  401.  
  402.         fLineHeight = 0;                        // Invalidate the font information
  403.     }
  404. }
  405.  
  406.  
  407.  
  408. //
  409. //    CFontSpec::SetMode
  410. //
  411. //
  412.  
  413. void CFontSpec::SetMode(short mode)
  414. {
  415.     // When the mode is changed, it is not necessary to invalidate the font information
  416.     fMode = mode;
  417. }
  418.  
  419.  
  420.  
  421. //
  422. //    CFontSpec::GetFontMetrics
  423. //
  424. //
  425.  
  426. void CFontSpec::GetFontMetrics(short& lineHeight,
  427.                             short& ascent,
  428.                             short& descent)
  429. {
  430.     // If the font info is not up to date...
  431.     if (fLineHeight == 0)                        
  432.     {
  433.         // ... recalc it
  434.         CFontSpec saveFont;
  435.         saveFont.Save();
  436.         FontInfo fi;
  437.         Use();                                    // Set the port to use the font info
  438.         ::GetFontInfo(&fi);                        // Get the font metrics
  439.         saveFont.Restore();
  440.         fAscent = fi.ascent;
  441.         fDescent = fi.descent;
  442.         fLineHeight = fi.ascent + fi.descent + fi.leading;
  443.  
  444.         assert(fLineHeight != 0);
  445.     }
  446.  
  447.     // Return the values now stored in the cache
  448.     lineHeight = fLineHeight;
  449.     ascent = fAscent;
  450.     descent = fDescent;
  451. }
  452.  
  453.  
  454.  
  455. //
  456. //    CFontSpec::TruncString
  457. //
  458. //
  459.  
  460. void CFontSpec::TruncString(short width,
  461.                             Str255 string,
  462.                             TruncCode where)
  463. {
  464.     Boolean supportCondense;
  465.     assert(width > 0);
  466.  
  467.     supportCondense = SupportCondense(GetScriptCode());
  468.  
  469.     // if script supports condensed style, clear it
  470.     if (supportCondense)
  471.         SetStyle(GetStyle() & ~condense);
  472.  
  473.     CFontSpec saveFont;
  474.     saveFont.Save();
  475.     Use();
  476.     if (StringWidth(string) > width)
  477.     {
  478.         // If script supports condensed style, use it
  479.         if (supportCondense)
  480.         {
  481.             SetStyle(GetStyle() | condense);
  482.             Use();
  483.  
  484.             // If failed to condense enough, truncate
  485.             if (StringWidth(string) > width)
  486.                 ::TruncString(width, string, where);
  487.         }
  488.         else
  489.         {
  490.             ::TruncString(width, string, where);
  491.         }
  492.     }
  493.     saveFont.Restore();
  494. }
  495.  
  496.  
  497.  
  498. //
  499. //    CFontSpec::MeasureString
  500. //
  501. //
  502.  
  503. short CFontSpec::MeasureString(ConstStr255Param string) const
  504. {
  505.     CFontSpec saveFont;
  506.     saveFont.Save();
  507.     Use();
  508.     short width = StringWidth(string);
  509.     saveFont.Restore();
  510.     return width;
  511. }
  512.  
  513.  
  514.  
  515. //
  516. //    CFontSpec::DrawString
  517. //
  518. //
  519.  
  520. void CFontSpec::DrawString(ConstStr255Param string) const
  521. {
  522.     CFontSpec saveFont;
  523.     saveFont.Save();
  524.     Use();
  525.     ::DrawString(string);
  526.     saveFont.Restore();
  527. }
  528.  
  529.  
  530. //
  531. //    CFontSpec::DrawText
  532. //
  533. //
  534.  
  535. void CFontSpec::DrawText(ConstStr255Param string,
  536.                          const CRect& bounds,
  537.                          short align) const
  538. {
  539.     if (string == NULL || string[0] == 0) return;
  540.     
  541.     CFontSpec saveFont;
  542.     saveFont.Save();
  543.     Use();
  544.     short endY;
  545.     short lhUsed;
  546.     (void)NeoTextBox(&string[1], string[0], bounds, align, -1, &endY, &lhUsed);
  547.     saveFont.Restore();
  548. }
  549.  
  550.  
  551.  
  552. //
  553. //    CFontSpec::TENew
  554. //
  555. //
  556.  
  557. TEHandle CFontSpec::TENew(void) const
  558. {
  559.     CFontSpec saveFont;
  560.     saveFont.Save();
  561.     Use();
  562.     Rect r;
  563.     SetRect(&r, 0, 0, 0, 0);
  564.     TEHandle text = ::TENew(&r, &r);
  565.     if (IsLeftToRight())
  566.         TESetAlignment(teFlushLeft, text);
  567.     else
  568.         TESetAlignment(teFlushRight, text);
  569.     saveFont.Restore();
  570.     return text;
  571. }
  572.  
  573.  
  574.  
  575. //
  576. //    CFontSpec::Use
  577. //
  578. //    Set the current port information to match the ones defined
  579. //    in the object. If they are already matching, no call to the
  580. //    Toolbox is made
  581. //
  582. //
  583.  
  584. void CFontSpec::Use() const
  585. {
  586.     assert(fScript != smNoScript);
  587.     
  588.     GrafPtr curPort;
  589.     GetPort(&curPort);
  590.  
  591.     // Must set the font first, because if size = 0, 
  592.     // it's depending on the script of the font
  593.  
  594.     if (curPort->txFont != fFont)
  595.         TextFont(fFont);
  596.  
  597.     if (curPort->txSize != fSize)
  598.         TextSize(fSize);
  599.  
  600.     if (curPort->txFace != fStyle)
  601.         TextFace(fStyle);
  602.  
  603.     if (curPort->txMode != fMode)
  604.         TextMode(fMode);
  605. }
  606.  
  607.  
  608.  
  609. void CFontSpec::SetPortFont(GrafPtr port) const
  610. {
  611.     GrafPtr savePort;
  612.     
  613.     // Save the current port
  614.     ::GetPort(&savePort);
  615.     
  616.     ::SetPort(port);
  617.  
  618.     // Must set the font first, because if size == 0, 
  619.     // it's depending on the script of the font
  620.  
  621.     if (port->txFont != fFont)
  622.         ::TextFont(fFont);
  623.  
  624.     if (port->txSize != fSize)
  625.         ::TextSize(fSize);
  626.  
  627.     if (port->txFace != fStyle)
  628.         ::TextFace(fStyle);
  629.  
  630.     if (port->txMode != fMode)
  631.         ::TextMode(fMode);
  632.     
  633.     // Restore the port
  634.     ::SetPort(savePort);
  635. }
  636.  
  637. const CFontSpec &CFontSpec::GetSystemFontSpec(void)
  638. {
  639.     if (!pSystemFontInited)
  640.     {
  641.         pSystemFontSpec.SetFont(smSystemScript, kSystemFont);
  642.         pSystemFontInited = true;
  643.     }
  644.     return pSystemFontSpec;
  645. }
  646.  
  647.  
  648. const CFontSpec &CFontSpec::GetSmallFontSpec(void)
  649. {
  650.     if (!pSmallFontInited)
  651.     {
  652.         pSmallFontSpec.SetFont(smSystemScript, kSmallFont);
  653.         pSmallFontInited = true;
  654.     }
  655.     return pSmallFontSpec;
  656. }
  657.  
  658.  
  659. Handle CFontSpec::GetIntlResource(short id)
  660. {
  661.     Handle h = NULL;
  662.     if (id == 0)
  663.     {
  664.         if (pItl0 == NULL)
  665.         {
  666.             h = FetchIntlResource(id);
  667.             assert(h != NULL);
  668.             HandToHand(&h);
  669.             HNoPurge(h);
  670.             pItl0 = h;
  671.         }
  672.         else
  673.         {
  674.             h = pItl0;
  675.         }
  676.     }
  677.     else if (id == 1)
  678.     {
  679.         if (pItl1 == NULL)
  680.         {
  681.             h = FetchIntlResource(id);
  682.             assert(h != NULL);
  683.             HandToHand(&h);
  684.             HNoPurge(h);
  685.             pItl1 = h;
  686.         }
  687.         else
  688.         {
  689.             h = pItl1;
  690.         }
  691.     }
  692.     else if (id == 2)
  693.     {
  694.         if (pItl2 == NULL)
  695.         {
  696.             h = FetchIntlResource(id);
  697.             assert(h != NULL);
  698.             HandToHand(&h);
  699.             HNoPurge(h);
  700.             pItl2 = h;
  701.         }
  702.         else
  703.         {
  704.             h = pItl2;
  705.         }
  706.     }
  707.     else
  708.     {
  709.         h = FetchIntlResource(id);
  710.     }
  711.     return h;
  712. }
  713.  
  714.  
  715. Handle CFontSpec::FetchIntlResource(short id)
  716. {
  717.     CFontSpec saveFont;
  718.     saveFont.Save();
  719.     GetSystemFontSpec().Use();
  720.     Handle h = ::GetIntlResource(id);
  721.     saveFont.Restore();
  722.     return h;
  723. }
  724.